#include "MCSegmentVisual.h"
#include <MCUtils.h>
#include <MCSettings.h>
#include <MCGripPoint.h>
#include <MCMathUtils.h>
#include <iostream>

MCSegmentVisual::MCSegmentVisual(ICanvas *presenter, const MCLineSegment2D &segment) :
    MCGraphicsItem(presenter),
    _segment(segment)
{
    gripPoints.push_back(new MCGripPoint(this, StartPoint, 0, _segment.startPoint()));
    gripPoints.push_back(new MCGripPoint(this, EndPoint, 1, _segment.endPoint()));
    gripPoints.push_back(new MCGripPoint(this, MidPoint, 2, _segment.midPoint()));
}

void MCSegmentVisual::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
    setPainter(painter);

    drawLineSegment(transformed().startPoint(), transformed().endPoint());
}

QPainterPath MCSegmentVisual::shape() const
{
    static const qreal kClickTolerance = MCSettings::LineClickableZone;
    MCLineSegment2D drawing = transformed();
    auto ep = drawing.endPoint();
    auto sp = drawing.startPoint();

    QPointF end_p = QPointF(ep.x, ep.y);
    QPointF start_p = QPointF(sp.x, sp.y);

    QPointF vec = end_p - start_p;

    if (qSqrt(QPointF::dotProduct(vec, vec) != 0))
    {
        vec = vec * (kClickTolerance / qSqrt(QPointF::dotProduct(vec, vec)));
    }

    QPointF orthogonal(vec.y(), -vec.x());

    QPainterPath result(start_p - vec + orthogonal);
    result.lineTo(start_p - vec - orthogonal);
    result.lineTo(end_p + vec - orthogonal);
    result.lineTo(end_p + vec + orthogonal);
    result.closeSubpath();

    return result;
}

void MCSegmentVisual::update(const MCPoint2D &p1, const MCPoint2D &p2)
{
    _segment.update(p1, p2);
    resetGrips();
}

void MCSegmentVisual::update(const MCPoint2D &sp, const MCVector2 &direction, double length)
{
    _segment = MCLineSegment2D(sp, direction, length);
    resetGrips();
}

void MCSegmentVisual::update(double angle)
{
    _segment.rotate(angle);
    resetGrips();
}

void MCSegmentVisual::update(const MCLineSegment2D &segment)
{
    _segment = segment;
    resetGrips();
}

const MCLineSegment2D &MCSegmentVisual::lineSegment()
{
    return _segment;
}

void MCSegmentVisual::setGripAt(IGripPoint *grip, const MCPoint2D &pos)
{
    if (grip->index() == 0)
    {
        _segment = MCLineSegment2D(pos, _segment.endPoint());
    }
    else if (grip->index() == 1)
    {
        _segment = MCLineSegment2D(_segment.startPoint(), pos);
    }
    else if (grip->index() == 2)
    {
        _segment.move(pos - _segment.midPoint());
    }

    resetGrips();
}

void MCSegmentVisual::resetGrips()
{
    gripPoints[0]->update(_segment.startPoint());
    gripPoints[1]->update(_segment.endPoint());
    gripPoints[2]->update(_segment.midPoint());
}

MCLineSegment2D MCSegmentVisual::transformed() const
{
    MCPoint2D p1 = presenter->screenToWorld(_segment.startPoint());
    MCPoint2D p2 = presenter->screenToWorld(_segment.endPoint());

    return MCLineSegment2D(p1, p2);
}
